home *** CD-ROM | disk | FTP | other *** search
/ Oh!X 2001 Spring / Oh!X 2001 Spring Special CD-ROM (Japan).7z / Oh!X 2001 Spring Special CD-ROM (Japan) (Track 1).bin / GALAXY / ohx5-1 / dplaydrive.cpp < prev    next >
C/C++ Source or Header  |  2001-01-10  |  14KB  |  515 lines

  1. /*
  2.     Oh!X5号
  3.     GalaxyKnightsサンプル1
  4.     Copyright(c)2000,Cyberhead,Inc.
  5.     DirectPlayドライブモジュール
  6.     殆ど無変更です。
  7. */
  8.  
  9. #include    "stdafx.h"
  10. #include    "ohx5_1.h"
  11. #include    <dplay.h>
  12.  
  13. LPDIRECTPLAY4    lpDP;
  14. HANDLE            DPhandle;                // DirectPlay で受信に用いるイベント・オブジェクトのハンドル
  15. HANDLE            ReceiverHandle;            // メッセージ受信スレッドのハンドル
  16. DWORD            ReceiverID;                // メッセージ受信スレッドのスレッドID
  17. bool            newdataf = false;        //    新規データ、または同期データを送るフラグ
  18. int                lost_count = 0;            //    パケットロストに対応するため、同期データを送るためのカウンタ
  19.  
  20. char    NAMESTR[]="OhX4_GalaxyKnights";    //    アプリケーション名
  21. char    PLAYERNAME[]="GK_Player";        //    プレイヤー名
  22.  
  23. #define    PLAYERS_LOOKS    4                //    プレイヤー外見(今回はトーラス,mapctrl.cppの物体リストを参照)
  24. #define    MYSELF_LOOKS    0                //    自分から見た自分の姿(今回は「無し」を指定)
  25.  
  26. DWORD WINAPI Receiver(LPVOID lpParams);
  27. void    make_status_container( status_container *cp );
  28.  
  29. // {B01FFB24-C957-11D3-827A-0000F460DD22}
  30. static const GUID guid_data = 
  31. { 0xB01FFB24, 0xC957, 0x11D3, { 0x82, 0x7A, 0x00, 0x00, 0xF4, 0x60, 0xDD, 0x22 } };
  32.  
  33. //    DirectPlayオブジェクトを作成する
  34. bool    init_directplay()
  35. {
  36. HRESULT    hr;
  37.     CoInitialize(NULL);
  38.     hr = CoCreateInstance(
  39.         CLSID_DirectPlay,
  40.         NULL,
  41.         CLSCTX_INPROC_SERVER,
  42.         IID_IDirectPlay4A,
  43.         (LPVOID *)&lpDP );
  44.     if( FAILED(hr) ){ return false; }
  45.     DPhandle = CreateEvent(NULL, FALSE, FALSE, NULL);
  46.     if (DPhandle == NULL){
  47.         lpDP->Release();
  48.         return false;
  49.     }
  50.     ReceiverHandle = CreateThread( NULL, 0, Receiver, NULL, 0, &ReceiverID );
  51.  
  52.     if ( ReceiverHandle == NULL ){
  53.         lpDP->Release();
  54.         CloseHandle( DPhandle );
  55.         return false;
  56.     }
  57.     return true;
  58. }
  59.  
  60. //    新しいプレイヤーを登録する
  61. DPPlayer    *new_player( DPID player_ID,DWORD name )
  62. {
  63. DPPlayer *dpp;
  64.     dpp = new DPPlayer;
  65.     dpp->back = NULL;
  66.     dpp->next = player_top;
  67.     if( player_top!=NULL ) player_top->back = dpp;
  68.     player_top = dpp;
  69.     if( name != 0 ){ dpp->objp = make_object( name ); } else { dpp->objp = NULL; }
  70.     dpp->dplayID = player_ID;
  71.     return dpp;
  72. }
  73.  
  74. //    プレイヤーを一人抹消
  75. void    kill_player( DPPlayer *dpp )
  76. {
  77.     if( dpp==NULL ) return;
  78.     if( player_top == dpp ) player_top = player_top->next;
  79.     if( dpp->back!=NULL ) dpp->back->next = dpp->next;
  80.     if( dpp->next!=NULL ) dpp->next->back = dpp->back;
  81.     if( dpp->objp != NULL )    delete_object( dpp->objp );
  82.     xDelete( dpp );
  83. }
  84.  
  85. //    DirectPlayオブジェクトの解放
  86. //    プレイヤーも全て消去する
  87. void    release_directplay()
  88. {
  89. DPPlayer    *dpp,*ndp;
  90.     xRelease( lpDP );
  91.     CoUninitialize();
  92.     dpp = player_top;
  93.     while( dpp != NULL ){
  94.         ndp = dpp->next;
  95.         kill_player( dpp );
  96.         dpp = ndp;
  97.     }
  98.     player_top = NULL;
  99. }
  100.  
  101. //    プレイヤーリストからプレイヤーを特定する
  102. DPPlayer    *scan_players( DPID    player_ID )
  103. {
  104. DPPlayer    *dpp = player_top;
  105.     while( dpp != NULL ){
  106.         if( dpp->dplayID == player_ID ) return dpp;
  107.         dpp = dpp->next;
  108.     }
  109.     return dpp;    //    見つからなかった=NULL
  110. }
  111.  
  112. //    キー操作パケットの送信
  113. void    send_player_control( DPID id,DWORD key )
  114. {
  115. HRESULT    hr;
  116. DPMSG_GENERIC        msgpack;
  117. status_container    scon;
  118.     if( multiplayer == FALSE ) return;
  119.     if( newdataf==true ){    // 自分の現在の状態を既に参加しているメンバーに伝える
  120.         newdataf = false;
  121.         make_status_container( &scon );
  122.         hr = lpDP->Send( id, DPID_ALLPLAYERS, 0, &scon, sizeof(status_container) );
  123.     } else {
  124.         lost_count--;
  125.         if( lost_count<=0 ){    //    パケットロストに対応するため、120サイクルに1回は、データを丸投げする
  126.             lost_count = 120;
  127.             newdataf = true;
  128.         }
  129.         msgpack.dwType = ( key<<16 )| dpmsg_data_packet;
  130.         hr = lpDP->Send( id, DPID_ALLPLAYERS, 0, &msgpack, sizeof(DPMSG_GENERIC));
  131.     }
  132. }
  133.  
  134. //    自分自身を生成する(開始直後はシングルプレイヤー)
  135. void    make_myself()
  136. {
  137.         myself = new_player( 0,0 );
  138.         myself->objp = make_object( MYSELF_LOOKS );
  139.         multiplayer = false;
  140. }
  141.  
  142. // サービス・プロバイダーの列挙
  143.  
  144. BOOL CALLBACK collect_probiders_callback(LPCGUID guid, LPVOID lpcp, DWORD size, LPCDPNAME name, DWORD flag, LPVOID context )
  145. {
  146. HWND hwnd = (HWND)context;
  147. LRESULT lr;
  148. LPVOID lpbuf;
  149.  
  150.     lr = SendDlgItemMessage(
  151.         hwnd,
  152.         IDC_COMBOSP,
  153.         CB_ADDSTRING,
  154.         0, (LPARAM)name->lpszShortName );
  155.  
  156.     if ( lr == CB_ERR ){ return TRUE; }
  157.  
  158.     // サービス・プロバイダの情報を格納するメモリを確保する
  159.     lpbuf = GlobalAlloc( GPTR, size );
  160.     if ( lpbuf == NULL ){ return TRUE; }
  161.  
  162.     // サービス・プロバイダの情報をコピーし,コンボ・ボックスのアイテム・データとして割り当てる
  163.     memcpy( lpbuf, lpcp, size );
  164.     SendDlgItemMessage(
  165.         hwnd,
  166.         IDC_COMBOSP,
  167.         CB_SETITEMDATA,
  168.         (WPARAM)lr,
  169.         (LPARAM)lpbuf );
  170.  
  171.     return TRUE;
  172. }
  173.  
  174. //    プロバイダリストの解放
  175. void release_probiderlist(HWND hwnd, int items)
  176. {
  177. int max, i;
  178. LPVOID lp;
  179.  
  180.     max = SendDlgItemMessage(
  181.         hwnd,
  182.         items,
  183.         CB_GETCOUNT,
  184.         0, 0 );
  185.     for (i = 0; i < max; i++){
  186.         lp = (LPVOID)SendDlgItemMessage(
  187.             hwnd,
  188.             items,
  189.             CB_GETITEMDATA,
  190.             i, 0);
  191.         GlobalFree(lp);
  192.     }
  193.     SendDlgItemMessage(
  194.         hwnd,
  195.         items,
  196.         CB_RESETCONTENT,
  197.         0, 0);
  198. }
  199.  
  200. // セッションの列挙
  201.  
  202. BOOL CALLBACK collect_sessions(LPCDPSESSIONDESC2 sessions, LPDWORD timeout, DWORD flag, LPVOID context)
  203. {
  204. HWND hwnd = (HWND)context;
  205. LPGUID guid;
  206. LONG pt;
  207.  
  208.     if ( flag & DPESC_TIMEDOUT) { return FALSE; }
  209.  
  210. //    列挙で得たセッションリストをリストボックスに溜める
  211.     pt = SendDlgItemMessage(
  212.         hwnd,
  213.         IDC_SESSIONS,
  214.         LB_ADDSTRING,
  215.         0,
  216.         (LPARAM)sessions->lpszSessionName );
  217.  
  218.     if ( pt == CB_ERR ) return TRUE;
  219.  
  220. //    セッションのガイドデータベースを作成、格納
  221.     guid = (LPGUID)GlobalAlloc(GPTR, sizeof(GUID));
  222.     if ( guid == NULL )    return TRUE;
  223.     *guid = sessions->guidInstance;
  224.     SendDlgItemMessage(
  225.         hwnd,
  226.         IDC_SESSIONS,
  227.         LB_SETITEMDATA,
  228.         (WPARAM)pt,
  229.         (LPARAM)guid );
  230.  
  231.     return TRUE;
  232. }
  233.  
  234. //    セッションリスト解放
  235. void release_sessions(HWND hwnd, int item)
  236. {
  237. int        max, i;
  238. LPVOID    lpt;
  239.  
  240.     max = SendDlgItemMessage(
  241.         hwnd,
  242.         item,
  243.         LB_GETCOUNT,
  244.         0, 0);
  245.     for( i = 0; i <max; i++ ){
  246.         lpt = (LPVOID)SendDlgItemMessage( hwnd, item, LB_GETITEMDATA, i, 0 );
  247.         GlobalFree( lpt );
  248.     }
  249.     SendDlgItemMessage(
  250.         hwnd,
  251.         item,
  252.         LB_RESETCONTENT,
  253.         0, 0);
  254. }
  255.  
  256. //    セッション選択ダイアログウインドウ
  257. BOOL CALLBACK session_dialog_proc(HWND handle, UINT Msg, WPARAM wParam, LPARAM lParam)
  258. {
  259. HRESULT            hr;
  260. DPSESSIONDESC2    sdesc;
  261. int                sno;
  262. int                retval = TRUE;
  263.  
  264.     switch( Msg ){
  265.     case WM_INITDIALOG:    //    セッション一覧作成
  266.         memset(&sdesc, 0, sizeof(DPSESSIONDESC2));
  267.         sdesc.dwSize = sizeof(DPSESSIONDESC2);
  268.         sdesc.guidApplication = guid_data;
  269.         
  270.         hr = lpDP->EnumSessions(&sdesc, 0, collect_sessions, handle, DPENUMSESSIONS_AVAILABLE);
  271.         if (FAILED(hr))    {
  272.             MessageBox(handle, "セッション一覧が作れません", "コネクト失敗", MB_OK | MB_ICONWARNING);
  273.             release_sessions(handle, IDC_SESSIONS);
  274.             EndDialog(handle, FALSE);
  275.         }
  276.         return TRUE;
  277.     case WM_COMMAND:    //    セッション参加or新規作成
  278.         switch (wParam) {
  279.         case IDOK:    //    OKボタンが押された=選択したセッションを受け取る
  280.             sno =    SendDlgItemMessage(handle, IDC_SESSIONS, LB_GETCURSEL, 0, 0);
  281.             memset(&sdesc, 0, sizeof(DPSESSIONDESC2));
  282.             if ( sno != LB_ERR ){ //    セッション起動
  283.                 GUID *guidsession;
  284.                 sdesc.dwSize = sizeof(DPSESSIONDESC2);
  285.                 guidsession = (GUID *)SendDlgItemMessage(handle, IDC_SESSIONS, LB_GETITEMDATA, sno , 0);
  286.                 sdesc.guidInstance = *guidsession;
  287.  
  288.                 // 既存のセッションに接続
  289.                 hr = lpDP->Open(&sdesc, DPOPEN_JOIN);
  290.                 if ( FAILED(hr) ) retval = FALSE;
  291.             } else { // OKボタンを押したとき、セッション未選択=新しいセッションを作る
  292.                 sdesc.dwSize = sizeof(DPSESSIONDESC2);
  293.                 sdesc.dwFlags = DPSESSION_MIGRATEHOST | DPSESSION_KEEPALIVE;
  294.                 sdesc.guidApplication = guid_data;
  295.                 sdesc.dwMaxPlayers = MAXPLAYERS;
  296.                 sdesc.lpszSessionNameA = NAMESTR;
  297.                 
  298.                 // セッションの新規作成
  299.                 hr = lpDP->Open(&sdesc, DPOPEN_CREATE);
  300.                 if( FAILED(hr) ) retval = FALSE; 
  301.             }
  302.             release_sessions( handle, IDC_SESSIONS );
  303.             EndDialog( handle, retval );
  304.             return TRUE;
  305.         case IDCANCEL:
  306.             release_sessions(handle, IDC_SESSIONS );
  307.             EndDialog(handle, FALSE);
  308.             return TRUE;        
  309.         default:
  310.             return FALSE;
  311.         }
  312.     default:
  313.         return FALSE;
  314.     }
  315.     return TRUE;
  316. }
  317.  
  318. // サービスプロバイダーリスト選択用ダイアログウインドウ
  319. BOOL CALLBACK probiderlist_dialog_proc(HWND handle, UINT Msg, WPARAM wParam, LPARAM lParam)
  320. {
  321.     HRESULT hr;
  322.     int iSelectedProvider;
  323.     LPVOID lpConnection;
  324.  
  325.     switch( Msg ){
  326.     case WM_INITDIALOG:    // サービスプロバイダーリスト作成
  327.         release_probiderlist(handle, IDC_COMBOSP);
  328.         lpDP->EnumConnections(NULL, collect_probiders_callback, handle, 0);
  329.         return TRUE;
  330.  
  331.     case WM_COMMAND:
  332.         switch (wParam)    {
  333.         case IDOK:
  334.             // [OK]ボタンが押されたときの処理
  335.             iSelectedProvider =    SendDlgItemMessage(handle, IDC_COMBOSP, CB_GETCURSEL, 0, 0);
  336.             if (iSelectedProvider != CB_ERR) {
  337.                 // サービス・プロバイダを初期化する
  338.                 lpConnection = (LPVOID)SendDlgItemMessage(handle, IDC_COMBOSP, CB_GETITEMDATA, iSelectedProvider, 0);
  339.                 hr = lpDP->InitializeConnection(lpConnection, 0);
  340.                 release_probiderlist(handle, IDC_COMBOSP);
  341.                 if ( SUCCEEDED(hr) || (hr == DPERR_ALREADYINITIALIZED) ){
  342.                     EndDialog(handle, TRUE);
  343.                 } else {
  344.                     MessageBox(handle, "サービスプロバイダーの初期化に失敗しました", NAMESTR, MB_OK | MB_ICONWARNING);
  345.                     EndDialog(handle, FALSE);
  346.                 }
  347.             } else {
  348.                 MessageBox(handle, "サービスプロバイダーを設定してください", NAMESTR, MB_OK | MB_ICONWARNING);
  349.             }
  350.             return TRUE;
  351.         case IDCANCEL:
  352.             release_probiderlist(handle, IDC_COMBOSP);
  353.             EndDialog(handle, FALSE);
  354.             return TRUE;
  355.         default:
  356.             return FALSE;
  357.         }
  358.         break;
  359.     default:
  360.         return FALSE;
  361.     }
  362.     return TRUE;
  363. }
  364.  
  365. //    対戦モードにする
  366. void    connect_player( HWND hwnd )
  367. {
  368. HRESULT    hr;
  369. DPID    dID;
  370. //    セッション開始
  371. //    マルチプレイヤーモードにする
  372.     multiplayer = true;
  373.     if (DialogBox(hInst, MAKEINTRESOURCE(IDD_CONNECT), hwnd, (DLGPROC)probiderlist_dialog_proc)){
  374. // セッション選択のダイアログ・ボックスを表示する
  375.         if (DialogBox(hInst, MAKEINTRESOURCE(IDD_SESSION), hwnd, (DLGPROC)session_dialog_proc)){
  376.             // プレーヤーを作成する
  377.             DPNAME dpName;
  378.                             
  379.             // プレーヤーの名前を設定
  380.             memset(&dpName, 0, sizeof(DPNAME));
  381.             dpName.dwSize = sizeof(DPNAME);
  382.             dpName.lpszShortNameA = PLAYERNAME;
  383.             dpName.lpszLongNameA = NULL;
  384.                             
  385.             // プレーヤーの作成
  386.             hr = lpDP->CreatePlayer( &dID, &dpName, DPhandle, NULL, 0, 0);
  387.             // 作成したプレーヤーのDPIDを保存
  388.             myself->dplayID = dID;
  389.             newdataf = true;
  390.  
  391.             InvalidateRect(hwnd, NULL, TRUE);
  392.             UpdateWindow(hwnd);
  393.         }
  394.     }
  395. }
  396.  
  397. //    回線切断する
  398. //    自分以外のプレイヤーを消去
  399. //    セッションを終了
  400. //    シングルプレイヤーモードにする
  401. void    disconnect_player( HWND hwnd )
  402. {
  403. DPPlayer    *dpp,*ndp;
  404.     multiplayer = false;
  405.     if (myself->dplayID != NULL)    {    // プレーヤーの削除
  406.         lpDP->DestroyPlayer( myself->dplayID );
  407.         myself->dplayID = NULL;
  408.         dpp = player_top;
  409.         while( dpp != NULL ){
  410.             ndp = dpp->next;
  411.             if( dpp != myself ) kill_player( dpp );
  412.             dpp = ndp;
  413.         }
  414.         InvalidateRect(hwnd, NULL, TRUE);
  415.         UpdateWindow(hwnd);
  416.     }
  417.     lpDP->Close();
  418. }
  419.  
  420. //    既存プレイヤーを生成する
  421. void    preset_player( DPPlayer *dpp,status_container *cp )
  422. {
  423.     dpp->objp->pos    = cp->position;
  424.     dpp->objp->rotate = cp->rotation;
  425.     dpp->objp->rudder = cp->rudder;
  426.     dpp->objp->move   = cp->speed;
  427.     dpp->objp->type   = cp->name;
  428. }
  429.  
  430. //    自分の情報をデータコンテナに詰め込む
  431. void    make_status_container( status_container *cp )
  432. {
  433.     cp->dwType   = dpmsg_now_status;
  434.     cp->name     = PLAYERS_LOOKS;
  435.     cp->position = myself->objp->pos;
  436.     cp->rotation = myself->objp->rotate;
  437.     cp->rudder   = myself->objp->rudder;
  438.     cp->speed    = myself->objp->move;
  439. }
  440.  
  441. //    メッセージ送受信のスレッドを用意
  442. DWORD WINAPI Receiver(LPVOID lpParams)
  443. {
  444.     // メッセージを受信するスレッド
  445. DPID    fromID,toID;
  446. LPDPMSG_GENERIC msgbuf;
  447. DWORD    msgbufsize;
  448. HRESULT stat,hr;
  449. HWND hwnd;
  450. DPPlayer    *dpp;
  451. status_container    scon;
  452.     hwnd = (HWND)lpParams;
  453.     while (WaitForSingleObject(DPhandle, INFINITE) == WAIT_OBJECT_0) {
  454.         //メッセージの取り出し
  455.         msgbuf = NULL;
  456.         msgbufsize = 0;
  457.         stat = DP_OK;    
  458.         while( SUCCEEDED( stat ) ){
  459.             stat = lpDP->Receive(
  460.                     &fromID,
  461.                     &toID,
  462.                     DPRECEIVE_ALL,
  463.                     NULL,
  464.                     &msgbufsize );            // 受信バッファ作成
  465.             if( stat != DPERR_BUFFERTOOSMALL ) break;
  466.             if( msgbuf != NULL ) GlobalFree( msgbuf );
  467.             if( ( msgbuf = (LPDPMSG_GENERIC)GlobalAlloc( GPTR, msgbufsize ) )==NULL ){
  468.                 stat = DPERR_OUTOFMEMORY;
  469.                 break;
  470.             }
  471.             // データを受信
  472.             stat = lpDP->Receive(
  473.                     &fromID,
  474.                     &toID,
  475.                     DPRECEIVE_ALL,
  476.                     msgbuf,
  477.                     &msgbufsize );
  478.             if( FAILED(stat) ) break;
  479.  
  480.             // 受信したメッセージの処理
  481.             switch( fromID ){
  482.             case DPID_SYSMSG:    // システム・メッセージ
  483.                 switch ( msgbuf->dwType ) {
  484.                 case DPSYS_CREATEPLAYERORGROUP://ユーザーが作られた
  485.                     //    新規参加者のために自分の状態を告げる
  486.                     make_status_container( &scon );
  487.                     hr = lpDP->Send(myself->dplayID,DPID_ALLPLAYERS, 0, &scon, sizeof(status_container));
  488.                     break;
  489.                 case DPSYS_DESTROYPLAYERORGROUP://ユーザーが減った
  490.                     dpp = scan_players( ((LPDPMSG_DESTROYPLAYERORGROUP)msgbuf)->dpId );
  491.                     kill_player( dpp );
  492.                     break;
  493.                 }
  494.                 break;
  495.             default:    //    各々のプレイヤーの挙動データ処理
  496.                 dpp = scan_players( fromID );
  497.                 if( dpp == NULL ){    //    相手は新規
  498.                     dpp = new_player( fromID, PLAYERS_LOOKS );
  499.                     dpp->objp->type = 0;    //    外見無しにしておく
  500.                 }
  501.                 if( msgbuf->dwType == dpmsg_now_status ){
  502.                     preset_player( dpp,(status_container *)msgbuf );
  503.                 } else {
  504.                     command_player( dpp->objp, *( (DWORD *)msgbuf ) );
  505.                 }
  506.             }
  507.         }
  508.         if( msgbuf != NULL ) GlobalFree( msgbuf );
  509.     }
  510.  
  511.     ExitThread(0);
  512.     return 0;
  513. }
  514.  
  515.